#include "ParseParam.h"
#include <map>
#include <set>
#include "DumpLog.h"
#include "HelpFun.h"
namespace Parse
{

bool parseParam(char **params, int paramNum, const vecParseParam_t &vecParam)
{
    //1.
    std::size_t num(0);
    std::map<std::string, const ParseParam_t*> mapParam;
    for (auto &it : vecParam)
    {
        //1.1
        if (it.key.empty())
        {
            LogError("命令行参数[{}]的key不能为空", it.name);
            return false;
        }

        //1.2
        mapParam.emplace(it.key, &it);
        if (num == mapParam.size())
        {
            LogError("命令行参数[{}]的key={}已经存在", it.name, it.key);
            return false;
        }

        //1.3
        num = mapParam.size();
    }

    //2.
    std::set<const ParseParam_t*> setKey;
    if (paramNum > 2)
    {
        int64_t nv;
        long double lv;
    
        for (int i = 1; i + 1 < paramNum; ++i)
        {
            //2.1
            std::string key(params[i]);
            if (key.empty())
            {
                continue;
            }

            //2.2
            if (key[0] != '-' || key.size() == 1)
            {
                continue;
            }

            //2.3
            key = key.substr(1, key.size() - 1);
            auto it = mapParam.find(key);
            if (it == mapParam.end())
            {
                continue;
            }

            //2.4
            ++i;
            setKey.insert(it->second);
            const std::string note("参数[- " + it->first +"]获取失败");
            switch (it->second->type)
            {
            case ParamType_E::String_E:
                *static_cast<std::string*>(it->second->value) = params[i];
                break;

            case ParamType_E::Int32_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(), note))
                {
                    return false;
                }

                *static_cast<int32_t*>(it->second->value) = nv;
                break;

            case ParamType_E::Double_E:
                if (!Help::tryToDouble(params[i], lv, 0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max(), note))
                {
                    return false;
                }

                *static_cast<double*>(it->second->value) = lv;
                break;

            case ParamType_E::Float_E:
                if (!Help::tryToDouble(params[i], lv, 0, std::numeric_limits<float>::min(), std::numeric_limits<float>::max(), note))
                {
                    return false;
                }

                *static_cast<float*>(it->second->value) = lv;
                break;

            case ParamType_E::LDouble_E:
                if (!Help::tryToDouble(params[i], lv, 0, std::numeric_limits<long double>::min(), std::numeric_limits<long double>::max(), note))
                {
                    return false;
                }

                *static_cast<long double*>(it->second->value) = lv;
                break;

            case ParamType_E::Int8_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(), note))
                {
                    return false;
                }

                *static_cast<int8_t*>(it->second->value) = nv;
                break;

            case ParamType_E::Int16_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max(), note))
                {
                    return false;
                }

                *static_cast<int16_t*>(it->second->value) = nv;
                break;

            case ParamType_E::Int64_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(), note))
                {
                    return false;
                }

                *static_cast<int64_t*>(it->second->value) = nv;
                break;
            
            case ParamType_E::UInt8_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<uint8_t>::min(), std::numeric_limits<uint8_t>::max(), note))
                {
                    return false;
                }

                *static_cast<uint8_t*>(it->second->value) = nv;
                break;

            case ParamType_E::UInt16_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<uint16_t>::min(), std::numeric_limits<uint16_t>::max(), note))
                {
                    return false;
                }

                *static_cast<uint16_t*>(it->second->value) = nv;
                break;

            case ParamType_E::UInt32_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max(), note))
                {
                    return false;
                }

                *static_cast<uint32_t*>(it->second->value) = nv;
                break;
            
            case ParamType_E::UInt64_E:
                if (!Help::tryToInt64(params[i], nv, 0, std::numeric_limits<uint64_t>::min(), std::numeric_limits<uint64_t>::max(), note))
                {
                    return false;
                }

                *static_cast<uint64_t*>(it->second->value) = nv;
                break;

            default:
                continue;
            }
        }
    }

    //3.
    for (auto &it : vecParam)
    {
        if (!it.need || setKey.count(&it))
        {
            continue;
        }

        LogError("没有设置参数[-{}]参数", it.key);
        return false;
    }

    //4.
    return true;
}

inline void appendSpace(std::size_t n)
{
    while (n)
    {
        --n;
        std::cout << " ";
    }
}

void printCmd(const vecParseParam_t &vecParam, const std::string &tip)
{
    //1.
    std::map<ParamType_E, std::string> mapStr
    {
        {ParamType_E::Double_E, "double"},
        {ParamType_E::Float_E, "float"},
        {ParamType_E::String_E, "string"},
        {ParamType_E::Int32_E, "int32"},
        {ParamType_E::Int64_E, "int64"},
        {ParamType_E::Int16_E, "int16"},
        {ParamType_E::Int8_E, "int8"},
        {ParamType_E::UInt32_E, "uint32"},
        {ParamType_E::UInt64_E, "uint64"},
        {ParamType_E::UInt16_E, "uint16"},
        {ParamType_E::UInt8_E, "uint8"},
        {ParamType_E::LDouble_E, "long double"},
    };

    std::string colorRed, colorGreen, colorYellow, colorReset, typeStr;
    std::size_t nameSize(0), keySize(0), noteSize(0), typeSize(0), n;
    Log::DumpLog::getGlobalLog().getCoutColor(colorRed, colorGreen, colorYellow, colorReset);
    for (auto &param : vecParam)
    {
        //1.1
        if (param.name.size() > nameSize)
        {
            nameSize = param.name.size();
        }

        //1.2
        if (param.key.size() > keySize)
        {
            keySize = param.key.size();
        }

        //1.3
        n = param.note.find('\n');
        if (n == std::string::npos)
        {
            n = param.note.size();
        }

        if (n > noteSize)
        {
            noteSize = n;
        }

        //1.4
        typeStr = mapStr[param.type];
        if (typeStr.size() > typeSize)
        {
            typeSize = typeStr.size();
        }
    }

    //2.
    std::string splitLine;
    splitLine.resize(nameSize + keySize + noteSize + typeSize + 6);
    std::fill(splitLine.begin(), splitLine.end(), '-');
    splitLine.push_back('\n');

    //3.
    std::cout << splitLine << "功能: " << colorRed << tip << colorReset << "\n" << splitLine;

    //4.
    {
        std::string skey("");
        std::string line = "./" + Help::getExeName() + " ";
        std::size_t lNum = line.size();
        for (auto &param : vecParam)
        {
            if (param.need)
            {
                skey = "-" + param.key + " " + param.name;
            }
            else
            {
                skey = "[-" + param.key + " " + param.name + "]";
            }

            if (line.size() + skey.size() > splitLine.size())
            {
                std::cout << line << "\n";
                line.resize(lNum);
                std::fill(line.begin(), line.end(), ' ');
            }

            line += skey + " ";
        }

        if (line.size())
        {
            std::cout << line;
        }
    }
    std::cout << "\n" << splitLine;

    //5.
    for (auto &param : vecParam)
    {
        //5.1
        std::cout << param.name;
        appendSpace(nameSize - param.name.size());
        
        //5.2
        std::cout << ": -" << param.key;
        appendSpace(keySize - param.key.size());

        //5.3
        typeStr = mapStr[param.type];
        std::cout << ", " << typeStr;
        appendSpace(typeSize - typeStr.size());

        //5.4
        std::cout << ", [";
        if (param.need)
        {
            std::cout << colorRed << "必须";
        }
        else
        {
            std::cout << colorGreen << "可选";
        }

        std::cout << colorReset << "], " << param.note << "\n";
    }

    //6.
    std::cout << splitLine;
}

}